"""Module for common testing code."""

import difflib
import os
import re
import sys
import types


def TestScratchDir(name):
  """Returns a temp dir that exists.

  Args:
    name: A string to separate the temp directory from other tests.
  """
  # TODO(andychu): Clean up the temp directories after all the tests have been
  # run.

  if sys.platform == 'win32':
    base_dir = r'c:\tmp'
  else:
    base_dir = r'/tmp'
  temp_dir = os.path.join(base_dir, name) + os.sep
  try:
    os.makedirs(temp_dir)
  except OSError:
    pass
  return temp_dir


def assertMatchesRegex(test, string, regex):
  match = re.match(regex, string)
  if not match:
    test.fail("%r did not match regex %r" % (string, regex))


def assertMatchesRegexLoose(test, string, regex):
  """Like the above, but uses re.search instead of re.match

  re.search is nicer when you want to search for a substring in a string with
  newlines.
  """
  match = re.search(regex, string)
  if not match:
    test.fail("%r did not (loosely) match regex %r" % (string, regex))


def assertEqual(test, left, right):
  """
  This function is just like unittest.TestCase.assertEqual, except you can pass
  a generator as the left argument, and it will convert it to a list, for easy
  testing.
  """
  if type(left) is types.GeneratorType:
    left = list(left)
  test.assertEqual(left, right)


def assertSequencesEqual(test, left, right):
  """
  Makes failures easier to read.
  """
  left_lines = [str(element) + '\n' for element in left]
  right_lines = [str(element) + '\n' for element in right]

  test.assertEqual(
      left, right,
      '\n' + '\n'.join(difflib.ndiff(left_lines, right_lines)))
  test.assertEqual(left, right)


def assertSameElements(test, left, right):
  """Compare containers without regard to order."""
  if type(left) is types.GeneratorType:
    left = list(left)
  left.sort()
  right.sort()
  test.assertEqual(left, right)


def assertContains(test, needle, haystack):
  """Test for membership."""
  if type(haystack) is types.GeneratorType:
    haystack = list(haystack)
  test.assert_(needle in haystack, '%r is not in %r' % (needle, haystack))


def assertEndsWith(test, s, suffix):
  test.assert_(s.endswith(suffix), '%r does not end with %r' % (s, suffix))


def assertStartsWith(test, s, prefix):
  test.assert_(s.startswith(prefix), '%r does not start with %r' % (s, prefix))


def assertHasSubstring(test, string, substring):
  test.assert_(
      substring in string,
      '%r is not a substring of %r' % (substring, string))


# TODO: Should this not be a special method?  In assertEqual, we could just
# test if the strings are more than one line.
def assertMultilineEqual(test, left, right):
  # TODO: Have a verbose level that prints the real strings.  Whitespace is
  # difficult to see with difflib.ndiff.
  #print 'L', repr(left)
  #print 'R', repr(right)
  test.assertEqual(
      left, right,
      '\n' + '\n'.join(difflib.ndiff(left.splitlines(), right.splitlines())))


class ObjectMock(object):
  def __init__(self, **kwargs):
    self.kwargs = kwargs

  def __getattr__(self, attr):
    return_value = self.kwargs[attr]
    def method(*_, **__):
      return return_value
    return method

